package com.zzyl.serve.service.impl;

import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.ShowDeviceRequest;
import com.huaweicloud.sdk.iotda.v5.model.ShowDeviceResponse;
import com.zzyl.common.constant.RedisKeyConstant;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.serve.domain.*;
import com.zzyl.serve.dto.BindingElderDto;
import com.zzyl.serve.dto.DeviceDataDto;
import com.zzyl.serve.dto.DeviceDataPageReqDto;
import com.zzyl.serve.dto.UserLoginRequestDto;
import com.zzyl.serve.mapper.ElderMapper;
import com.zzyl.serve.mapper.FamilyMemberElderMapper;
import com.zzyl.serve.service.*;
import com.zzyl.serve.vo.FamilyMemberElderVo;
import com.zzyl.serve.vo.LoginVo;
import com.zzyl.serve.vo.PageFamilyMemberElderVo;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.batch.BatchProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.serve.mapper.FamilyMemberMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 老人家属Service业务层处理
 * 
 * @author itheima
 * @date 2025-03-12
 */
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService
{
    @Autowired
    private FamilyMemberMapper familyMemberMapper;


    /**
     * 查询老人家属
     * 
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询老人家属列表
     * 
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember)
    {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember)
    {
        return save(familyMember) ? 1 : 0;
    }

    /**
     * 修改老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember)
    {
        return updateById(familyMember) ? 1 : 0;
    }

    /**
     * 批量删除老人家属
     * 
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除老人家属信息
     * 
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }


    @Autowired
    private WechatService webschatService;

    @Autowired
    private TokenService tokenService;

    /**
     *  小程序端 用户登录的逻辑处理
     * @param dto
     * @return
     */
    @Override
    public LoginVo login(UserLoginRequestDto dto) {


        //1.根据code调用微信api获取apenId
        String openid = webschatService.getOpenid(dto.getCode());

        //2.根据openId查询数据库获取用户信息family_member表
        FamilyMember familyMember = getOne(
                new LambdaQueryWrapper<FamilyMember>()
                        .eq(FamilyMember::getOpenId, openid)
        );

        //3.调用微信api获取用户绑定手机号
        String phone = webschatService.getPhone(dto.getPhoneCode());


        //4.判断用户信息是否存在，如果不存在，则新增family_member表
        //5.存在则 修改family_member表数据
        if(ObjectUtil.isNull(familyMember)){
            // 新用户


            familyMember = new FamilyMember();
            familyMember.setPhone(phone);
            familyMember.setOpenId(openid);

            // 设置初始随机名称
            familyMember.setName("花开富贵" + DateUtils.getTime());

            save(familyMember);

        }else {
            // 老用户
            familyMember.setPhone(phone);
            updateById(familyMember);
        }


        //6.将用户id存入token中，并返回数据给前端
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", familyMember.getId());
        claims.put("nickName", familyMember.getName());

        String token = tokenService.createToken(claims);
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(familyMember.getName());
        return loginVo;
    }


    @Autowired
    IElderService elderService;

    @Autowired
    IContractService contractService;

    @Autowired
    FamilyMemberElderMapper familyMemberElderMapper;

    /**
     * 绑定老人
     * @param dto
     */
    @Override
    public void bindFamilyMember(BindingElderDto dto) {
        // 判断绑定内容是否为空
        if(ObjectUtil.isEmpty(dto)) {
            throw new RuntimeException("绑定内容不能为空");
        }
        //校验身份证是否合规
        String idCardNo = dto.getIdCard();
        String regularExpression = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +
                "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
        if(!idCardNo.matches(regularExpression)) {
            throw new RuntimeException("身份证号格式不对");
        }
        Elder theElder = elderService.getOne(new LambdaQueryWrapper<Elder>()
                .eq(Elder::getName, dto.getName())
                .eq(Elder::getIdCardNo, idCardNo));
        Contract contract = contractService.getOne(new LambdaQueryWrapper<Contract>()
                .eq(Contract::getElderId, theElder.getId()));
        if(ObjectUtil.isEmpty(contract)) {
            throw new RuntimeException("该老人不存在");
        }

        // 获取当前用户id
        Long familyMemberId = UserThreadLocal.getUserId();
        Long id = theElder.getId();
        List<FamilyMemberElder> familyMemberElders = familyMemberElderMapper.selectList(new LambdaQueryWrapper<FamilyMemberElder>()
                .eq(FamilyMemberElder::getFamilyMemberId, familyMemberId));
        for (FamilyMemberElder familyMemberElder : familyMemberElders) {
            if(id.equals(familyMemberElder.getElderId())) {
                throw new RuntimeException("已绑定过此家人");
            }
        }

        //绑定老人
        FamilyMemberElder familyMemberElder = new FamilyMemberElder();

        //获取当前用户（家属）id,封装信息
        familyMemberElder.setFamilyMemberId(familyMemberId);
        familyMemberElder.setElderId(theElder.getId());
        familyMemberElder.setRemark(dto.getRemark());
        //保存绑定信息
        familyMemberElderMapper.insert(familyMemberElder);
    }

    /**
     * 查询家人列表
     */
    @Override
    public List<FamilyMemberElderVo> queryFamilyMemberElderList() {

        List<FamilyMemberElder> familyMemberElders = familyMemberElderMapper.selectList(new LambdaQueryWrapper<FamilyMemberElder>());
        // 创建返回集合
        List<FamilyMemberElderVo> voList = new ArrayList<>();
        //遍历关联表对象
        familyMemberElders.forEach(familyMemberElder -> {
            //遍历获取老人姓名
            Long elderId = familyMemberElder.getElderId();
            Elder elder = elderService.getById(elderId);
            String elderName = elder.getName();
            // 封装vo对象
            FamilyMemberElderVo familyMemberElderVo = BeanUtil.toBean(familyMemberElder, FamilyMemberElderVo.class);
            familyMemberElderVo.setElderName(elderName);
            voList.add(familyMemberElderVo);
        });

        return voList;
    }

    @Autowired
    private IBedService bedService;

    @Autowired
    private IRoomService roomService;

    @Autowired
    private IDeviceService deviceService;

    /**
     * 分页查询家人列表
     */
    @Override
    public List<PageFamilyMemberElderVo> pageFamilyMemberElder() {
        Integer familyMemberId = Math.toIntExact(UserThreadLocal.getUserId());
        List<PageFamilyMemberElderVo> voList = new ArrayList<>();
        // 获取中间表列表
        List<FamilyMemberElder> familyMemberElderList = familyMemberElderMapper.selectList(new LambdaQueryWrapper<FamilyMemberElder>()
                .eq(FamilyMemberElder::getFamilyMemberId, familyMemberId));
        // 遍历中间表, 获取其他信息，封装对象
        familyMemberElderList.forEach(familyMemberElder -> {
            PageFamilyMemberElderVo vo = new PageFamilyMemberElderVo();

            // 封装中间表信息
            vo.setMid(familyMemberElder.getId());
            vo.setMremark(familyMemberElder.getRemark());
            Long elderId = familyMemberElder.getElderId();
            vo.setElderId(elderId);

            // 获取老人信息,封装老人信息
            Elder elder = elderService.getOne(new LambdaQueryWrapper<Elder>().eq(Elder::getId, elderId));
            BeanUtils.copyProperties(elder, vo);

            //查询封装房间类型(typeName)
            Bed bed = bedService.getOne(new LambdaQueryWrapper<Bed>().eq(Bed::getId, elder.getBedId()));
            Room room = roomService.getOne(new LambdaQueryWrapper<Room>().eq(Room::getId, bed.getRoomId()));
            vo.setTypeName(room.getTypeName());

            // 查询封装设备信息(老人的随身设备)
            Device device = deviceService.getOne(new LambdaQueryWrapper<Device>().eq(Device::getBindingLocation, elderId));
            if(!ObjectUtil.isEmpty(device)) {
                BeanUtils.copyProperties(device, vo);
            }

            voList.add(vo);
        });

        return voList;
    }

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 查询老人健康数据
     */
    @Override
    public List<Map<String, Object>> queryServiceProperties(String iotId) {
        List<Map<String, Object>> list = new ArrayList<>();
        String jsonStr = JSONUtil.toJsonStr(redisTemplate.opsForHash().get(RedisKeyConstant.IOT_DEVICE_LAST_DATA, iotId));
        List<DeviceData> deviceDataList = JSONUtil.toList(jsonStr, DeviceData.class);
        deviceDataList.forEach(deviceData -> {
            Map<String, Object> map = new HashMap<>();
            map.put("functionId", deviceData.getFunctionId());
            map.put("eventTime", deviceData.getAlarmTime());
            map.put("value", deviceData.getDataValue());
            list.add(map);
        });
        return list;
    }

    @Autowired
    private IDeviceDataService deviceDataService;
    /**
     * 按天统计查询指标数据
     */
    @Override
    public List<Map<String, Object>> queryDeviceDataListByDay(DeviceDataDto dto) {
        List<Map<String, Object>> list = new ArrayList<>();
        //查询设备对应的数据
        LocalDateTime startTime = LocalDateTimeUtil.of(dto.getStartTime());
        LocalDateTime endTime = LocalDateTimeUtil.of(dto.getEndTime());
        List<DeviceData> deviceDataList = deviceDataService.list(new LambdaQueryWrapper<DeviceData>()
                .eq(DeviceData::getIotId, dto.getIotId())
                .between(DeviceData::getAlarmTime, startTime, endTime));
        // 遍历查找对应的属性
        deviceDataList.forEach(deviceData -> {
            String functionId = dto.getFunctionId();
            Map<String, Object> map = new HashMap<>();
            if(functionId.equals(deviceData.getFunctionId())) {
                //转换日期格式
                String dateTime = deviceData.getAlarmTime().format(DateTimeFormatter.ofPattern("HH:mm"));
                map.put("dateTime", dateTime);

                // 数值保留一位小数
                DecimalFormat df = new DecimalFormat("#.0");
                String value = df.format(Double.valueOf(deviceData.getDataValue()));
                map.put("dataValue", Double.valueOf(value));
                list.add(map);
            }
        });
        return list;
    }

    /**
     * 按周统计查询指标数据
     */
    @Override
    public List<Map<String, Object>> queryDeviceDataListByWeek(DeviceDataDto dto) {
        List<Map<String, Object>> list = new ArrayList<>();
        //查询设备对应的数据
        LocalDateTime startTime = LocalDateTimeUtil.of(dto.getStartTime());
        LocalDateTime endTime = LocalDateTimeUtil.of(dto.getEndTime());
        List<DeviceData> deviceDataList = deviceDataService.list(new LambdaQueryWrapper<DeviceData>()
                .eq(DeviceData::getIotId, dto.getIotId())
                .between(DeviceData::getAlarmTime, startTime, endTime));
        // 遍历查找对应的属性
        deviceDataList.forEach(deviceData -> {
            String functionId = dto.getFunctionId();
            Map<String, Object> map = new HashMap<>();
            if(functionId.equals(deviceData.getFunctionId())) {
                //转换日期格式
                String dateTime = deviceData.getAlarmTime().format(DateTimeFormatter.ofPattern("MM.dd"));
                map.put("dateTime", dateTime);



                map.put("dataValue", deviceData.getDataValue());
                list.add(map);

            }
        });
        // 将相同日期map合并，只保留平均值
        DecimalFormat df = new DecimalFormat("#.0");
        List<Map<String, Object>> result = list.stream()
                // 按dateTime分组
                .collect(Collectors.groupingBy(
                        map -> (String) map.get("dateTime"),
                        Collectors.averagingDouble(map -> (Double) map.get("dataValue")
//                          return Double.valueOf(df.format(Double.valueOf((String)map.get("dataValue"))));
                         )
                ))
                // 将分组后的平均值转换回Map结构
                .entrySet().stream()
                .map(entry -> {
                    Map<String, Object> newMap = new HashMap<>();
                    newMap.put("dateTime", entry.getKey());
                    newMap.put("dataValue", entry.getValue());
                    return newMap;
                })
                .collect(Collectors.toList());
        // 按照日期进行升序排序
        result = result.stream()
                .sorted(Comparator.comparing(map -> (String) map.get("dateTime")))
                .collect(Collectors.toList());
        /*result = result.stream()
                .sorted(Comparator.comparing(map -> (String) map.get("dateTime")).reversed())
                .collect(Collectors.toList());*/

        return result;
    }
}
